import React, { Component } from "react";
import { flushSync } from "react-dom";

class DemoSetStateAdvance extends Component {
    state = {
        x: 1,
        y: 2,
        z: 3,
    };
    handle = () => {
        // this => 实例 【宿主环境】
        console.log('this实例====', this);
        
        // 三次setState 都在定时器中，值更新一次
        // setTimeout(() => {
        //     this.setState({
        //         x: 10,
        //     }, () => {
        //         console.log('x更新完毕');
        //         console.log('xxxxxx更新后的值',this.state.x);
        //     });
        //     console.log('xxxxxx',this.state);
        // }, 2000);

        // setTimeout(() => {
        //     this.setState({
        //         y: 20,
        //     }, () => {
        //         console.log('y更新完毕');
        //         console.log('yyyyyy更新后的值',this.state.y);
        //     });
        //     console.log('yyyyyy',this.state);
        // }, 2001);

        // setTimeout(() => {
        //     this.setState({
        //         z: 30,
        //     }, () => {
        //         console.log('z更新完毕');
        //         console.log('zzzzzz更新后的值',this.state.z);
        //     });
        //     console.log('zzzzzz',this.state);
        // }, 2002);
        let { x, y } = this.state;
        this.setState({
            x: x + 1,
        });
        console.log(this.state);
        flushSync(() => {
            this.setState({
                y: y + 1,
            });
            console.log(this.state);
        }); // flushSync操作结束之后会立即刷新更新队列，批处理统一更新一次
        // 在修改z之前必须保证x y 已经更改且试图更新
        console.log(this.state);
        this.setState({
            z: this.state.x + this.state.y
        });
    };
    render() {
        console.log('视图渲染');
        let { x, y, z } = this.state; 
        return (
            <>
                <div>
                    x:{x} - y:{y} - z:{z}
                </div>
                <br />
                <button onClick={this.handle}>按钮</button>
            </>
        )
    };
    // shouldComponentUpdate() {
    //     return false;
    // };
    componentDidUpdate() {
        console.log('componentDidUpdate------组件更新完毕');
    };
};

export default DemoSetStateAdvance;

/**
 * // 同时修改三个状态值，只会触发一次视图更新
 * // 调用三次setState修改三个状态，
 * this.setState(partialState, callback)
 *     [partialState]: 支持部分状态更改
 *          this.setState({ 
 *              x: 100,
 *              y: 200,
 *              z: 300,
 *          })
 * 
 *      [callback]: 在状态更改，视图更新完毕之后执行
    *      [componentDidUpdate周期函数之后执行]
    *      可有效解决大部分setState更新状态时候的异步问题
    *      componentDidUpdate会在任何状态更新之后执行
    *      callback可以在指定状态更新后处理一些事情类似于vue中的$nextTick
    *      即便基于shoudComponentUpdate函数中return false; 阻止了状 和视图的更新和componentDidUpdate周期函数的执行，但是依旧会触 callback回调函数
 * 
 */ 

/**
 * 在React18中所有的setState都是异步操作
 *  +React18中有一套更新队列的机制
 *  基于异步操作，实现状态的”批处理“
 * 好处：
 *  有效减少更新次数，降低性能消耗
 *  让更新的逻辑和流程更清晰稳健
 * 
 * 过程：
 *  不会直接更新状态和视图，而是加到更新队列（updater）中
 *  在产生的私有上下文中，代码自上而下运行
 *      @1会把所有的同时间能处理的setState操作先添加到更新队列（不等定时器等异步的代码中setState），【只对当前上下文，同步要做的事情做处理】
 *      @2当上下文中的代码都处理完毕之后，会将更新队列中的任务，统一渲染/更新一次（批处理）
 *          shouldUpdate
 *          willUpdate
 *          修改状态
 *          render
 *          didUpdate
 *          callback  
 *      @3定时器时间到了的时候 重复有以上@1 @2 操作，再统一渲染一次
 */

/* 
    React18中无论在什么地方，setState都是异步的，都是基于updater更新队列机制实现批处理
    React16中，如果在合成事件（jsx元素基于onXxxx绑定的时间），周期函数中setState操作是异步的。但是如果setState出现在其他异步操作中，例如【定时器，手动获取dom元素绑定的事件】，setState将变为同步操作立即更新状态让视图渲染。
*/

/*
    如何在react18中实现x, y 更新之后再更新z。（不使用定时器）
*/